/***************************************************************************
 *   Copyright (C) 2008 by BogDan Vatra                                    *
 *   bogdan@licentia.eu                                                    *
 *                                                                         *
 *   This program is free software: you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation, either version 3 of the License, or     *
 *   (at your option) any later version.                                   *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program.  If not, see <http://www.gnu.org/licenses/>. *
 ***************************************************************************/

#include <QSettings>
#include <QPainter>
#include <QSqlError>
#include <QInputDialog>
#include <QWebFrame>
#include <QDate>
#include <QDebug>
#include <kontamabilloader.h>
#include <baseinterface.h>
#include <menuwidgetinterface.h>

#include "operatiunicontabile.h"

OperatiuniContabile::OperatiuniContabile(QWidget* parent, Qt::WFlags fl)
		: KontAMabilWindow(parent, fl), Ui::operatiuniContabileForm()
{
	setupUi(this);
	connect(this, SIGNAL(aboutToShow()), SLOT(onAboutToShow()));
	connect(this, SIGNAL(aboutToClose()), SLOT(onAboutToClose()));
	defaultDatabase()->bindValue("luna",5);
	defaultDatabase()->bindValue("anul",2008);
	m_acteQry=defaultDatabase()->query("acte");
	m_opQry=defaultDatabase()->query("operatiuni");
	m_noteQry=defaultDatabase()->query("note");
	m_analiticeQry=defaultDatabase()->query("analitice_operatiuni");
	m_ocw = new OperatiuniContabileWidget;
	connect(m_ocw,SIGNAL(currentChanged(int, int)),SLOT(currentChanged(int, int)));
	connect(m_ocw,SIGNAL(editCell(int, int, const QRect&, const QString&)),SLOT(editCell(int, int, const QRect&, const QString&)));
	connect(m_ocw,SIGNAL(paintCell(int, int, QPainter&, const QRect&, int)),SLOT(paintCell(int, int, QPainter&, const QRect&, int)));
	connect(m_ocw,SIGNAL(deletePressed(int, int)),SLOT(deletePressed(int, int)));
	connect(m_ocw,SIGNAL(aboutToClose()),&m_infoView, SLOT(close()));
	m_contc="";
	m_contd="";
	m_suma=0;
	m_infoView.setWindowFlags(Qt::ToolTip);
	foreach(BaseInterface* plugin, kontAMabil()->basePlugins())
		if (dynamic_cast<AnaliticeInterface *>(plugin))
			m_analiticePlugins.push_back(dynamic_cast<AnaliticeInterface *>(plugin));

	foreach(MenuWidgetInterface* plugin, kontAMabil()->menuPlugins())
		if (dynamic_cast<AnaliticeInterface *>(plugin))
			m_analiticePlugins.push_back(dynamic_cast<AnaliticeInterface *>(plugin));
}

AnaliticeInterface * OperatiuniContabile::amPluginPentru(const QString & pluginName)
{
	foreach(AnaliticeInterface * plugin, m_analiticePlugins)
		if (plugin->tipAnalitic()==pluginName)
			return plugin;
	return 0;
}

void OperatiuniContabile::populeazaAnalitice()
{
	m_analiticeUnice.clear();
	m_analitice.clear();
	m_analitice.resize(m_opQry->size());
	if (!m_opQry->size())
		return;

	int rowNo=0;

	do
	{
		m_analiticeQry->bindValue("idoperatiune",m_opQry->value("id"));
		m_analiticeQry->bindValue("tip_cont","D");
		m_analiticeQry->select();
		if (m_analiticeQry->size())
		{
			do
			{
				AnaliticeInterface * plugin=amPluginPentru(m_analiticeQry->value("tip_analitic").toString());
				if (plugin)
				{
					_analitic a;
					a.id=m_analiticeQry->value("idanalitic").toDouble();
					a.tipAnalitic=m_analiticeQry->value("tip_analitic").toString();
					m_analitice[rowNo].debit.push_back(a);
					if (plugin->unicPeAct() && !m_analiticeUnice[m_opQry->value("contd").toString()].contains(a))
						m_analiticeUnice[m_opQry->value("contd").toString()].push_back(a);
				}
			}while(m_analiticeQry->next());
		}
		m_analiticeQry->bindValue("tip_cont","C");
		m_analiticeQry->select();
		if (m_analiticeQry->size())
		{
			do
			{
				AnaliticeInterface * plugin=amPluginPentru(m_analiticeQry->value("tip_analitic").toString());
				if (plugin)
				{
					_analitic a;
					a.id=m_analiticeQry->value("idanalitic").toDouble();
					a.tipAnalitic=m_analiticeQry->value("tip_analitic").toString();
					m_analitice[rowNo].credit.push_back(a);
					if (plugin->unicPeAct() && !m_analiticeUnice[m_opQry->value("contc").toString()].contains(a))
						m_analiticeUnice[m_opQry->value("contc").toString()].push_back(a);
				}
			}while(m_analiticeQry->next());
		}
		rowNo++;
	}while(m_opQry->next());
}

void OperatiuniContabile::puneAnalitice()
{
	QSqlQuery q(defaultDatabase()->database());
	q.exec("BEGIN");
	for (int i=0;i<m_opQry->size();i++)
	{
		m_opQry->seek(i);
		q.prepare("DELETE FROM analitice_operatiuni WHERE idoperatiune=:idoperatiune");
		q.bindValue(":idoperatiune",m_opQry->value("id"));
		q.exec();
		foreach(_analitic a, m_analitice[i].debit)
		{
			q.prepare("INSERT INTO analitice_operatiuni (idoperatiune, idanalitic, tip_analitic, tip_cont) VALUES (:idoperatiune, :idanalitic, :tip_analitic, :tip_cont)");
			q.bindValue(":idoperatiune",m_opQry->value("id"));
			q.bindValue(":idanalitic",a.id);
			q.bindValue(":tip_analitic",a.tipAnalitic);
			q.bindValue(":tip_cont","D");
			if (!q.exec())
			{
				q.exec("ROLLBACK");
				qDebug()<<q.lastError().text();
				break;
			}
		}
		foreach(_analitic a, m_analitice[i].credit)
		{
			q.prepare("INSERT INTO analitice_operatiuni (idoperatiune, idanalitic, tip_analitic, tip_cont) VALUES (:idoperatiune, :idanalitic, :tip_analitic, :tip_cont)");
			q.bindValue(":idoperatiune",m_opQry->value("id"));
			q.bindValue(":idanalitic",a.id);
			q.bindValue(":tip_analitic",a.tipAnalitic);
			q.bindValue(":tip_cont","C");
			if (!q.exec())
			{
				q.exec("ROLLBACK");
				qDebug()<<q.lastError().text();
				break;
			}
		}
	}
	q.exec("COMMIT");
}

void OperatiuniContabile::adaugaOperatiune()
{
	m_analitice.resize(m_opQry->size()+1);
	if (!m_suma || !m_contc.length() || !m_contd.length())
		return;
	m_opQry->insert();
	m_opQry->setValue("idact",m_acteQry->value("id"));
	m_opQry->setValue("contc",m_contc);
	m_opQry->setValue("contd",m_contd);
	m_opQry->setValue("suma",m_suma);
	m_opQry->post();
	m_analitice.resize(m_opQry->size()+1);
	m_contc="";
	m_contd="";
	m_suma=0;
	m_ocw->setCurrentCell(0,m_ocw->currentCell().row+1);
}

void OperatiuniContabile::currentChanged(int col, int row)
{
	if (col>1 || row>=m_opQry->size())
	{
		m_infoView.close();
		return;
	}
	m_opQry->seek(row);
	QSqlQuery q(defaultDatabase()->database());
	q.prepare("select * from detalii_operatiune(:idop, :tipc)");
	q.bindValue(":idop",m_opQry->value("id"));
	q.bindValue(":tipc",col?"C":"D");
	if (!q.exec())
	{
		qDebug()<<q.lastQuery()<<q.lastError().text();
		m_infoView.close();
		return;
	}
	q.first();
	if (!q.value(0).toString().length())
	{
		m_infoView.close();
		return;
	}
	m_infoView.setHtml(q.value(0).toString());
	m_infoView.resize(m_ocw->frameGeometry().width(),m_ocw->frameGeometry().height()/2); //m_infoView.page()->mainFrame()->contentsSize());
	m_infoView.move(m_ocw->frameGeometry().bottomLeft());
	m_infoView.show();
}

void OperatiuniContabile::verificaAnaliticePentruCont(const QString & cont, AnaliticeInterface::TipCont tipCont)
{
	foreach(_analitic  a, m_analiticeUnice[cont])
	{
		if (tipCont==AnaliticeInterface::ContDebitor)
		{
			m_analitice[m_curRan].debit.removeAll(a);
			m_analitice[m_curRan].debit.push_back(a);
		}
		else
		{
			m_analitice[m_curRan].credit.removeAll(a);
			m_analitice[m_curRan].credit.push_back(a);
		}
	}

	bool checkUnic=m_analiticeUnice[cont].size();

	foreach(AnaliticeInterface * analitic, m_analiticePlugins)
	{
		_analitic a;
		if ( checkUnic && analitic->unicPeAct())
			continue;// daca acest analitic TREBUIE sa fie unic si am analitice pentru acest cont nu il mai cer !!!

		if (!analitic->amAnaliticPentru(this, cont, tipCont, a.id))
				continue; // daca nu vrea sa bage acest tip de analitic trec mai departe

		a.tipAnalitic=analitic->tipAnalitic();

		if (analitic->unicPeAct())
			m_analiticeUnice[cont].push_back(a);

		if (tipCont==AnaliticeInterface::ContDebitor)
		{
			if (!m_analitice[m_curRan].debit.contains(a))
				m_analitice[m_curRan].debit.push_back(a);
		}
		else
			if (!m_analitice[m_curRan].credit.contains(a))
				m_analitice[m_curRan].credit.push_back(a);
	}
}

void OperatiuniContabile::conturiEditingFinished()
{
	if (m_curRan>=m_opQry->size())
	{
		if (m_curCol)
			m_contc=m_conturiEdit->text();
		else
			m_contd=m_conturiEdit->text();
		adaugaOperatiune();
	}
	else
	{
		m_opQry->seek(m_curRan);
		m_opQry->update();
		m_opQry->setValue(m_curCol?"contc":"contd",m_conturiEdit->text());
		m_opQry->post();
	}
	verificaAnaliticePentruCont(m_conturiEdit->text(),m_curCol==0?AnaliticeInterface::ContDebitor:AnaliticeInterface::ContCreditor);
	m_ocw->setRows(m_opQry->size()+1);
	m_ocw->setCurrentCell(m_ocw->currentCell().col+1,m_ocw->currentCell().row);
}

void OperatiuniContabile::sumaEditingFinished()
{
	if (m_curRan>=m_opQry->size())
	{
		m_suma=m_sumaEdit->text().toDouble();
		adaugaOperatiune();
	}
	else
	{
		m_opQry->seek(m_curRan);
		if (!m_sumaEdit->text().toDouble())
		{
			m_analitice.remove(m_curRan);
			m_opQry->remove();
		}
		else
		{
			m_opQry->update();
			m_opQry->setValue("suma",m_sumaEdit->text());
			m_opQry->post();
			m_ocw->setCurrentCell(0,m_ocw->currentCell().row+1);
		}
	}
	m_ocw->setRows(m_opQry->size()+1);
}

void OperatiuniContabile::editCell(int col, int row, const QRect & rect, const QString & text)
{
	m_curCol=col;
	m_curRan=row;
	if (col<2)
	{
		m_conturiEdit = new LookupLineEdit(m_ocw);
		m_conturiEdit->setListQuery("planConturi");
		m_conturiEdit->setListField("cont");
		m_conturiEdit->setKeyField("id");
		m_conturiEdit->setInfoFields(QStringList()<<"tip"<<"denumire");
		m_conturiEdit->setInfoHeads(QStringList()<<"Tip"<<"Denumire");
		m_conturiEdit->setAppendPluginName("planConturi");
		m_conturiEdit->setSortedListField(true);
		m_conturiEdit->setValidateInput(true);
		m_conturiEdit->setGeometry(rect);
		m_conturiEdit->setVisible(true);
		m_conturiEdit->setFocus();
		if (text.length())
		{
			m_conturiEdit->setText(text);
			m_conturiEdit->setCursorPosition(text.length());
		}
		else
			if (row<m_opQry->size())
				m_conturiEdit->setText(m_opQry->value(col?"contc":"contd").toString());
			else
				m_conturiEdit->clear();
		connect(m_conturiEdit,SIGNAL(returnPressed()),SLOT(conturiEditingFinished()));
		connect(m_conturiEdit,SIGNAL(editingFinished()),m_ocw,SLOT(setFocus()));
		connect(m_conturiEdit,SIGNAL(editingFinished()),m_conturiEdit,SLOT(deleteLater()));
	}
	else
	{
		m_sumaEdit= new LineEdit(m_ocw);
		m_sumaEdit->setGeometry(rect);
		m_sumaEdit->setVisible(true);
		m_sumaEdit->setFocus();
		if (text.length())
		{
			m_sumaEdit->setText(text);
			m_sumaEdit->setCursorPosition(text.length());
		}
		else
			if (row<m_opQry->size())
				m_sumaEdit->setText(m_opQry->value("suma").toString());
			else
				m_sumaEdit->setText("0");
		connect(m_sumaEdit,SIGNAL(returnPressed()),SLOT(sumaEditingFinished()));
		connect(m_sumaEdit,SIGNAL(editingFinished()),m_sumaEdit,SLOT(deleteLater()));
		connect(m_sumaEdit,SIGNAL(editingFinished()),m_ocw,SLOT(setFocus()));
	}
}

void OperatiuniContabile::paintCell(int col, int row, QPainter & painter, const QRect & rect, int /*cellFlags*/)
{
	m_opQry->seek(row);
	QString text=(row>=m_opQry->size()?(col==0?m_contd:col==1?m_contc:QString("%1").arg(m_suma)):(col==0?m_opQry->value("contd").toString():col==1?m_opQry->value("contc").toString():m_opQry->value("suma").toString()));
	painter.drawText(rect,Qt::AlignVCenter|(col==1?Qt::AlignLeft:Qt::AlignRight),text);
}

void OperatiuniContabile::deletePressed(int col, int row)
{
	Q_UNUSED(col);
	if (row>=m_opQry->size())
		return;
	m_analitice.remove(row);
	m_opQry->seek(row);
	m_opQry->remove();
	m_ocw->setRows(m_opQry->size()+1);
	m_ocw->update();
}

bool OperatiuniContabile::cautaAct(const QString & numarAct, const QString & serieAct)
{
	bool gasit=false;
	while(m_acteQry->previous()) // merg inapoi pana la primul act diverit de numarul curent
		if (m_acteQry->value("numar")!=numarAct)
			break;

	while(m_acteQry->next())
		if (m_acteQry->value("numar")!=numarAct)
			break;
		else
			if (m_acteQry->value("serie")==serieAct)
			{
				gasit=true;
				break;
			}
	return gasit;
}

void OperatiuniContabile::hideNumar()
{
	m_acteQry->cancel();
	m_opQry->cancel();
	numarWidget->hide();
	layout()->activate();
	resize(QSize(width(), height() - ((y() + height()) - (numarWidget->y() + numarWidget->height()))));

}

void OperatiuniContabile::on_ziuaEdit_returnPressed()
{
	if (m_noteQry->value("numar")!=notaEdit->text())
	{
		hideNumar();
		notaEdit->setFocus();
		return;
	}
	if(!QDate::isValid(defaultDatabase()->boundValue("anul").toInt(), defaultDatabase()->boundValue("luna").toInt(), ziuaEdit->text().toInt()))
	{
		ziuaEdit->selectAll();
		return;
	}
	m_acteQry->cancel();
	m_acteQry->bindValue("idnota",m_noteQry->value("id"));
	m_acteQry->bindValue("ziua",ziuaEdit->text());
	m_acteQry->select();
	numarWidget->show();
	numarEdit->setFocus();
}

void OperatiuniContabile::on_numarEdit_returnPressed()
{
	if (cereSeriaButton->isChecked())
		seriaEdit->setFocus();
	else
		showOperatiuni();
}

void OperatiuniContabile::on_numarEdit_escapePressed()
{
	hideNumar();
	ziuaEdit->setFocus();
}

void OperatiuniContabile::on_seriaEdit_returnPressed()
{
	showOperatiuni();
}

void OperatiuniContabile::on_seriaEdit_escapePressed()
{
	hideNumar();
	ziuaEdit->setFocus();
}


void OperatiuniContabile::on_notaEdit_focusIn()
{
	hideNumar();
}

void OperatiuniContabile::on_ziuaEdit_focusIn()
{
	hideNumar();
}

void OperatiuniContabile::onAboutToClose()
{
	QSettings s;
	s.setValue("operatiuniContabile/cereSeria", cereSeriaButton->isChecked());
	KontAMabilWindow::accept();
}

void OperatiuniContabile::onAboutToShow()
{
	QSettings s;
	cereSeriaButton->setChecked(s.value("operatiuniContabile/cereSeria", false).toBool());
	hideNumar();
}

void OperatiuniContabile::on_cereSeriaButton_toggled(bool pushed)
{
	if (pushed)
	{
		cereSeriaButton->setText(tr("Nu cere &seria"));
		seriaEdit->setFocus();
	}
	else
	{
		seriaEdit->clear();
		cereSeriaButton->setText(tr("Cere &seria"));
		numarEdit->setFocus();
	}
}

void OperatiuniContabile::showOperatiuni()
{
	if (m_noteQry->value("numar")!=notaEdit->text())
	{
		hideNumar();
		notaEdit->setFocus();
		return;
	}

	if (!ziuaEdit->text().length())
	{
		hideNumar();
		ziuaEdit->setFocus();
		return;
	}

	if (!numarEdit->text().length())
		numarEdit->setText(tr("fara numar"));

	bool adaugAct=false;
	if (m_acteQry->value("numar")!=numarEdit->text() && !m_acteQry->locate("numar",numarEdit->text(),Query::CaseSensitive))
		adaugAct=true;
	else
		if (seriaEdit->isEnabled() && m_acteQry->value("serie")!=seriaEdit->text())
			adaugAct=!cautaAct(numarEdit->text(),seriaEdit->text());

	if (adaugAct)
	{
		m_acteQry->insert();
		m_acteQry->setValue("ziua",ziuaEdit->text());
		m_acteQry->setValue("idnota",m_noteQry->value("id"));
		m_acteQry->setValue("numar",numarEdit->text());
		m_acteQry->setValue("serie",seriaEdit->text());
		m_acteQry->post();
	}

	m_opQry->bindValue("idact",m_acteQry->value("id"));
	m_opQry->select();
	populeazaAnalitice();
	m_acteQry->update();
	m_ocw->setRows(m_opQry->size()+1);
	m_ocw->exec();
	if (m_opQry->size())
	{
		puneAnalitice();
		foreach(AnaliticeInterface * analitic, m_analiticePlugins)
			analitic->analizaAct();

		QSqlQuery q(defaultDatabase()->database());
		q.prepare("select * from explicatii_pentru_actul(:idact)");
		q.bindValue(":idact",m_acteQry->value("id"));

		QString explicatii=m_acteQry->value("explicatii").toString();

		if (!explicatii.length())
		{
			if (q.exec() && q.first())
				explicatii=q.value(0).toString();
			else
				qDebug()<<q.lastError().text();
		}

		QString explic=QInputDialog::getText(this,tr("Explicatii act"),tr("Explicatii pentu act:"), QLineEdit::Normal, explicatii);
		m_acteQry->setValue("explicatii",explic);
		m_acteQry->post();
	}
	else
	{
		m_acteQry->post();
		m_acteQry->remove();
	}
}

OperatiuniContabile::~OperatiuniContabile()
{
}

